package com.threeti.mecool.core.domain.model.plan.pojo;

import com.threeti.mecool.core.application.message.MessageService;
import com.threeti.mecool.core.domain.model.message.MobileMessage;
import com.threeti.mecool.core.domain.model.plan.PlanResult;
import com.threeti.mecool.core.exception.MessageException;
import com.threeti.mecool.core.infrastructure.persistence.plan.PlanRepository;
import org.codehaus.jackson.annotate.JsonManagedReference;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Configurable
@Entity
@Table(name = "DM_PLAN",
        uniqueConstraints = @UniqueConstraint(columnNames = {"userLoginName", "planDate", "type"}))
public class Plan {
    public static final String STATUS_NEW = "new";
    public static final String STATUS_CONFIRM = "confirm";
    public static final String STATUS_DENY = "deny";
    public static final String STATUS_CHANGE = "change";
    /**
     * 指派任务 *
     */
    public static final String TYPE_ASSIGNMENT = "assignment";

    private Long id;
    private Integer version;
    private String userLoginName;
    private String name;
    private Date planDate;
    private List<PlanProject> planProjects = new ArrayList<PlanProject>();
    private String status = STATUS_NEW;
    private String denyNotes;
    private String changeNotes;
    private String assignedBy;
    private String type;

    private PlanRepository planRepository;
    private MessageService messageService;

    //<editor-fold desc="static finder">
    public static Plan findById(Long id) {
        if (id == null) {
            return null;
        } else {
            return planRepository().findOne(id);
        }
    }

    public static Plan findUserDailyPlan(String userLoginName, Date planDate) {
        return planRepository().findByUserLoginNameAndPlanDateAndTypeIsNull(userLoginName, planDate);
    }

    public static Plan findUserAssignedPlan(String userLoginName, Date planDate) {
        return planRepository().findByUserLoginNameAndPlanDateAndType(userLoginName, planDate, Plan.TYPE_ASSIGNMENT);
    }

    public static Page<Plan> findBySpec(Specification<Plan> spec, Pageable pageable) {
        return planRepository().findAll(spec, pageable);
    }

    public static Plan optAssignedPlanBy(String userLoginName, String projectCode, String storeCode,
                                         Long jobId, Date planDate, Date startTime, Date endTime) {
        Plan plan = planRepository().findByUserLoginNameAndPlanDateAndType(userLoginName, planDate, Plan.TYPE_ASSIGNMENT);
        if (plan == null) {
            plan = new Plan();
            plan.setPlanDate(planDate);
            plan.setUserLoginName(userLoginName);
            plan.setName(new SimpleDateFormat("yyyy-MM-dd").format(planDate));
            plan.setType(Plan.TYPE_ASSIGNMENT);
            plan.setStatus(Plan.STATUS_CONFIRM);
        }
        PlanProject planProject = plan.optPlanProjectByProjectCode(projectCode);
        PlanJob planJob = planProject.optPlanJobByJobIdAndStoreCode(jobId, storeCode);
        planJob.setStartTime(startTime);
        planJob.setEndTime(endTime);
        return plan;
    }

    public static Page<Plan> findByUserLoginName(String userLoginName, Pageable pageable) {
        return planRepository().findByUserLoginName(userLoginName, pageable);
    }
    //</editor-fold>

    public void addPlanProject(PlanProject planProject) {
        planProject.setPlan(this);
        planProjects.add(planProject);
    }

    public PlanProject optPlanProjectByProjectCode(String projectCode) {
        for (PlanProject planProject : planProjects) {
            if (projectCode.equals(planProject.getProjectCode())) {
                return planProject;
            }
        }
        PlanProject planProject = new PlanProject();
        planProject.setProjectCode(projectCode);
        addPlanProject(planProject);
        return planProject;
    }

    @Transactional
    public void delete() {
        planRepository.delete(this);
    }

    @Transactional
    public void save() {
        MobileMessage mobileMessage = new MobileMessage();
        mobileMessage.setReceiver(userLoginName);
        mobileMessage.setCreator(userLoginName);
        mobileMessage.setHead("工作计划");
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        boolean sendMessage = false;
        if (!Plan.STATUS_NEW.equals(status)) {
//            Plan originPlan = Plan.findById(id);
//            if (!originPlan.getStatus().equals(status)) {
                sendMessage = true;
                if (Plan.STATUS_CONFIRM.equals(status)) {
                    mobileMessage.setBody("您有新的工作计划，计划日期：" + dateFormat.format(planDate));
                } else if (Plan.STATUS_DENY.equals(status)) {
                    mobileMessage.setBody("您的工作计划有变动，计划日期：" + dateFormat.format(planDate));
                }
//            }
        } else if (Plan.TYPE_ASSIGNMENT.equals(type)) {
            mobileMessage.setBody("您有新的工作计划，计划日期：" + dateFormat.format(planDate));
        }
        planRepository.save(this);
        if (Plan.STATUS_CONFIRM.equals(status)) {
            PlanResult planResult = PlanResult.optByPlanId(id);
            planResult.getPlanJobResults().clear();
            for (PlanProject planProject : planProjects) {
                for (PlanJob planJob : planProject.getPlanJobs()) {
                    planResult.optPlanJobResultByPlanJobId(planJob.getId());
                }
            }
            planResult.save();
        }
        if (sendMessage) {
            try {
                messageService.send(mobileMessage);
            } catch (MessageException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private static PlanRepository planRepository() {
        return new Plan().planRepository;
    }

    //<editor-fold desc="get/set">
    @Resource
    public void setMessageService(MessageService messageService) {
        this.messageService = messageService;
    }

    @Resource
    public void setPlanRepository(PlanRepository planRepository) {
        this.planRepository = planRepository;
    }

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    @Version
    public Integer getVersion() {
        return version;
    }

    @NotNull
    public String getUserLoginName() {
        return userLoginName;
    }

    @NotNull
    @Size(min = 1, max = 50)
    public String getName() {
        return name;
    }

    @Temporal(TemporalType.DATE)
    @NotNull
    public Date getPlanDate() {
        return planDate;
    }

    @JsonManagedReference
    @OneToMany(mappedBy = "plan", cascade = CascadeType.ALL, orphanRemoval = true)
    public List<PlanProject> getPlanProjects() {
        return planProjects;
    }

    @NotNull
    public String getStatus() {
        return status == null ? Plan.STATUS_NEW : status;
    }

    public String getChangeNotes() {
        return changeNotes;
    }

    public String getDenyNotes() {
        return denyNotes;
    }

    public String getAssignedBy() {
        return assignedBy;
    }

    public String getType() {
        return type;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    public void setUserLoginName(String userLoginName) {
        this.userLoginName = userLoginName;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setPlanDate(Date planDate) {
        this.planDate = planDate;
    }

    public void setPlanProjects(List<PlanProject> planProjects) {
        this.planProjects = planProjects;
    }

    public void setStatus(String status) {
        this.status = status.toLowerCase();
    }

    public void setDenyNotes(String denyNotes) {
        this.denyNotes = denyNotes;
    }

    public void setChangeNotes(String changeNotes) {
        this.changeNotes = changeNotes;
    }

    public void setAssignedBy(String assignedBy) {
        this.assignedBy = assignedBy;
    }

    public void setType(String type) {
        this.type = type;
    }
    //</editor-fold>
}
